#include <iostream>
#include <memory>


//###################################
struct A;
struct B;
struct A{
    std::shared_ptr<B> bptr;
    ~A(){
        std::cout << "A is deleted !" << std::endl;
    }
};

struct B{
    std::weak_ptr<A> aptr;
    ~B(){
        std::cout << "B is deleted !" << std::endl;
    }
};
//###################################

struct Foo{
    Foo(int a):m_a(a){
        std::cout << __FUNCTION__ << std::endl;
    }

    ~Foo(){
        std::cout << __FUNCTION__ << std::endl;
    }

    int m_a;
};

std::weak_ptr<Foo> gw;
void f()
{
    if(gw.expired())
    {
        std::cout << "gw is expired \n";
    }
    else
    {
        auto spt = gw.lock(); //但它可以使用一个非常重要的成员函数lock()从被观测的shared_ptr获得一个可用的shared_ptr对象，从而操作资源。
        spt.get()->m_a = 66; //能写
        std::cout << spt.get()->m_a<< "\n"; //能读
    }
}


int main(void)
{
    //使用 use_cout 获得当前观测资源的引用计数
    {

        std::shared_ptr<int> sp(new int(10));
        std::weak_ptr<int> wp(sp);

        std::cout << wp.use_count() << std::endl;
    }

    //使用 expired 方法来判断所观察的资源是否已经释放
    {

        std::shared_ptr<int> sp = std::make_shared<int>(10);
        std::shared_ptr<int> sp_n;
        std::weak_ptr<int> wp(sp_n);
        //std::weak_ptr<int> wp(sp);

        if(wp.expired())
            std::cout << "所监视的智能指针已被释放" << std::endl;
        else
            std::cout << "所监视的智能指针有效" << std::endl;
    }


    {
        //通过 lock 方法来获取所监视的shared_ptr
        {
            auto sp = std::make_shared<Foo>(42);
            //std::shared_ptr<Foo>sp(new Foo(42));
            gw = sp;
            f(); //shared_ptr有效
        }
        std::cout << "Line:" << __LINE__ << std::endl;
        f();  //shared_ptr 无效
        std::cout << "Line:"  << __LINE__ << std::endl;
    }

    {
        //weak_ptr 返回 this 指针
    }

    { //weak_ptr 解决循环引用问题
        std::shared_ptr<A> ap(new A);
        std::shared_ptr<B> bp(new B);

        ap->bptr = bp;
        bp->aptr = ap; 
        //在 bp->aptr = ap; 时，由于aptr 时 weak_ptr ，它并不会增加引用计数，所以 ap 的引用计数仍会是1，在离开作用域之后，ap 
        //的引用计数减为0，A 指针被析构，析构后其内部的bptr 的引用计数会减1，然后在离开作用域后，bp引用计数又从1
        //减为0，B对象也被析构，不会发生内存泄漏
    }

    return 0;
}
